/*
 * ConsoleLogger.java
 *
 * Created on July 26, 2007, 9:57 PM
 *
 *  Copyright (C) 2010 Tal Eisenberg
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package base;

import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.text.NumberFormat;
import tal.drivechain.chain.Chain;
import tal.drivechain.chain.ChainController;
import tal.drivechain.chain.ChainListener;
import tal.drivechain.chain.ChainNode;
import tal.drivechain.chain.ChainNode.MSG;
import tal.drivechain.system.Globals;

/**
 *
 * @author Main
 */
public class ConsoleController extends ChainController implements ChainListener {

    private NumberFormat timeFormat = NumberFormat.getNumberInstance();
    private final String NEW_LINE = System.getProperty("line.separator");
    private final int COLUMNS = 80;
    private boolean quit = false;

    @Override
    public void init(boolean timing, OutputStream out) {
        super.init(timing, out);
        setOutputStream(new PrintStream(out));
        if (this.properties.containsKey("doHold") && this.properties.get("doHold").equals("true")) {
            quit = true;
        }

        timeFormat.setMaximumFractionDigits(2);
    }

    public void setOutputStream(OutputStream out) {
        this.outputStream = new PrintStream(out);
    }

    public OutputStream getOutputStream() {
        return outputStream;
    }

    @Override
    public void logReceived(LogLine currentLog) {
        String message = currentLog.message;
        String src = currentLog.src;
        MSG type = currentLog.type;

        if (message == null) {
            message = "<null>";
        }
        if (message.indexOf("\n") != -1) {
            String[] split = message.split("\n");
            for (String line : split) {
                generalMessage(line, type, src);
            }
            return;
        }

        String stime = null;
        String stype = null;

        if (type == MSG.WARNING) {
            stype = "WARNING ";
        } else if (type == MSG.ERROR) {
            stype = "ERROR ";
        } else if (type == MSG.DEBUG) {
            stype = "DEBUG ";
        } else {
            stype = "";
        }
        if (timing) {
            stime = "<" + timeFormat.format(currentLog.time) + "ms> ";
        } else {
            stime = "";
        }

        if (src != null && src.trim().length() > 0) {
            src = src + "> ";
        } else {
            src = "";
        }
        String prefix = (stime + stype + src);

        outputStream.println(prefix + message);

    }

    private String format(String message, int tab) {
        boolean addNewLine = false;
        if (tab > 20) {
            tab = 5;
            addNewLine = true;
        }
        if (tab >= COLUMNS) {
            return format(message, tab - COLUMNS);
        }
        int line = COLUMNS - tab - 2;
        String sTab = "";
        for (int i = 0; i < (tab); i++) {
            sTab += " ";
        }

        if (message.length() <= line) {
            return message;
        } else {
            String formatted = "";

            //go thru each line and try to break it.
            //if the break there's no space after before or on the break
            //split on line length if not split on the space.
            int lineStart = 0;
            int curLineBreak = line;
            boolean finished = false;
            message = message.replaceAll("\n", " ").replaceAll("\t", " ").replace("\\s+", " ");
            while (!finished) {
                if (!(message.charAt(curLineBreak) == ' ' || (curLineBreak < (message.length() - 1) && message.charAt(curLineBreak + 1) == ' '))) {
                    int spaceIdx = message.lastIndexOf(" ", curLineBreak);
                    if (spaceIdx != -1 && spaceIdx > lineStart) {
                        curLineBreak = spaceIdx;
                    }
                }
                if (lineStart > 0) {
                    formatted += sTab;
                }
                formatted += message.substring(lineStart, curLineBreak).trim() + NEW_LINE;
                lineStart = curLineBreak;
                curLineBreak = lineStart + line;
                if (curLineBreak > message.length() - 1) {
                    if (lineStart < message.length() - 1) {
                        formatted += sTab + message.substring(lineStart).trim();
                    }
                    finished = true;
                }
            }
            if (addNewLine) {
                formatted = NEW_LINE + formatted;
            }
            return formatted;
        }
    }

    @Override
    public void takeOver() {
        this.runLogger();
        Globals.getRootChain().addChainListener(this);
        Globals.getRootChain().start();

        if (!quit) {
            System.out.println("\n--- Press enter to shutdown...\n");
        }
        try {
            while (!quit) {
                if (System.in.read() == 10) {
                    quit = true;
                }
            }
        } catch (IOException ie) {
            outputStream.println(ie.getMessage());
        }

        //close the main chain.
        Globals.getRootChain().stop();
        this.stopLogger();
    }

    public void chainStopped(Chain chain) {
    }

    public boolean chainStopping(Chain chain) {
        this.generalMessage("Shutting down...", MSG.ANOUNCE, "ConsoleController");
        return true;
    }

    public boolean chainStarting(Chain chain) {
        return true;
    }

    @Override
    public void println(String line) {
        outputStream.println(line);
    }

    public void nodeConfigured(Chain src, ChainNode mod) {}

    public void childRemoved(Chain src, ChainNode m) {}

    public void childAdded(Chain src, ChainNode m) {}

    public void childRenamed(Chain src, ChainNode child) {
    }

}